<?php
/*
 *  $Id$
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * This software consists of voluntary contributions made by many individuals
 * and is licensed under the LGPL. For more information, see
 * <http://www.doctrine-project.org>.
 */

/**
 * Doctrine_Formatter
 *
 * @package     Doctrine
 * @subpackage  Formatter
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @link        www.doctrine-project.org
 * @since       1.0
 * @version     $Revision$
 * @author      Konsta Vesterinen <kvesteri@cc.hut.fi>
 */
class Doctrine_Formatter extends Doctrine_Connection_Module
{
	/**
	 * Quotes pattern (% and _) characters in a string)
	 *
	 * EXPERIMENTAL
	 *
	 * WARNING: this function is experimental and may change signature at
	 * any time until labelled as non-experimental
	 *
	 * @param   string  the input string to quote
	 *
	 * @return  string  quoted string
	 */
	public function escapePattern($text)
	{
		if ( ! $this->string_quoting['escape_pattern']) {
			return $text;
		}
		$tmp = $this->conn->string_quoting;

		$text = str_replace($tmp['escape_pattern'],
		$tmp['escape_pattern'] .
		$tmp['escape_pattern'], $text);

		foreach ($this->wildcards as $wildcard) {
			$text = str_replace($wildcard, $tmp['escape_pattern'] . $wildcard, $text);
		}
		return $text;
	}

	/**
	 * convertBooleans
	 * some drivers need the boolean values to be converted into integers
	 * when using DQL API
	 *
	 * This method takes care of that conversion
	 *
	 * @param array $item
	 * @return void
	 */
	public function convertBooleans($item)
	{
		if (is_array($item)) {
			foreach ($item as $k => $value) {
				if (is_bool($value)) {
					$item[$k] = (int) $value;
				}
			}
		} else {
			if (is_bool($item)) {
				$item = (int) $item;
			}
		}
		return $item;
	}

	/**
	 * Quote a string so it can be safely used as a table or column name
	 *
	 * Delimiting style depends on which database driver is being used.
	 *
	 * NOTE: just because you CAN use delimited identifiers doesn't mean
	 * you SHOULD use them.  In general, they end up causing way more
	 * problems than they solve.
	 *
	 * Portability is broken by using the following characters inside
	 * delimited identifiers:
	 *   + backtick (<kbd>`</kbd>) -- due to MySQL
	 *   + double quote (<kbd>"</kbd>) -- due to Oracle
	 *   + brackets (<kbd>[</kbd> or <kbd>]</kbd>) -- due to Access
	 *
	 * Delimited identifiers are known to generally work correctly under
	 * the following drivers:
	 *   + mssql
	 *   + mysql
	 *   + mysqli
	 *   + oci8
	 *   + pgsql
	 *   + sqlite
	 *
	 * InterBase doesn't seem to be able to use delimited identifiers
	 * via PHP 4.  They work fine under PHP 5.
	 *
	 * @param string $str           identifier name to be quoted
	 * @param bool $checkOption     check the 'quote_identifier' option
	 *
	 * @return string               quoted identifier string
	 */
	public function quoteIdentifier($str, $checkOption = true)
	{
		if ($checkOption && ! $this->conn->getAttribute(Doctrine_Core::ATTR_QUOTE_IDENTIFIER)) {
			return $str;
		}
		$tmp = $this->conn->identifier_quoting;
		$str = str_replace($tmp['end'],
		$tmp['escape'] .
		$tmp['end'], $str);

		return $tmp['start'] . $str . $tmp['end'];
	}


	/**
	 * quoteMultipleIdentifier
	 * Quotes multiple identifier strings
	 *
	 * @param array $arr           identifiers array to be quoted
	 * @param bool $checkOption     check the 'quote_identifier' option
	 *
	 * @return string               quoted identifier string
	 */
	public function quoteMultipleIdentifier($arr, $checkOption = true)
	{
		foreach ($arr as $k => $v) {
			$arr[$k] = $this->quoteIdentifier($v, $checkOption);
		}

		return $arr;
	}

	/**
	 * quote
	 * quotes given input parameter
	 *
	 * @param mixed $input      parameter to be quoted
	 * @param string $type
	 * @return string
	 */
	public function quote($input, $type = null)
	{
		if ($type == null) {
			$type = gettype($input);
		}
		switch ($type) {
			case 'integer':
			case 'double':
			case 'float':
			case 'bool':
			case 'decimal':
			case 'int':
				return $input;
			case 'array':
			case 'object':
				$input = serialize($input);
			case 'date':
			case 'time':
			case 'timestamp':
			case 'string':
			case 'char':
			case 'varchar':
			case 'text':
			case 'gzip':
			case 'blob':
			case 'clob':
			case 'enum':
			case 'boolean':
				return "'" . str_replace("'","''",$input) . "'";
		}
	}

	/**
	 * Removes any formatting in an sequence name using the 'seqname_format' option
	 *
	 * @param string $sqn string that containts name of a potential sequence
	 * @return string name of the sequence with possible formatting removed
	 */
	public function fixSequenceName($sqn)
	{
		$seqPattern = '/^'.preg_replace('/%s/', '([a-z0-9_]+)',  $this->conn->getAttribute(Doctrine_Core::ATTR_SEQNAME_FORMAT)).'$/i';
		$seqName    = preg_replace($seqPattern, '\\1', $sqn);

		if ($seqName && ! strcasecmp($sqn, $this->getSequenceName($seqName))) {
			return $seqName;
		}
		return $sqn;
	}

	/**
	 * Removes any formatting in an index name using the 'idxname_format' option
	 *
	 * @param string $idx string that containts name of anl index
	 * @return string name of the index with possible formatting removed
	 */
	public function fixIndexName($idx)
	{
		$indexPattern   = '/^'.preg_replace('/%s/', '([a-z0-9_]+)', $this->conn->getAttribute(Doctrine_Core::ATTR_IDXNAME_FORMAT)).'$/i';
		$indexName      = preg_replace($indexPattern, '\\1', $idx);
		if ($indexName && ! strcasecmp($idx, $this->getIndexName($indexName))) {
			return $indexName;
		}
		return $idx;
	}

	/**
	 * adds sequence name formatting to a sequence name
	 *
	 * @param string    name of the sequence
	 * @return string   formatted sequence name
	 */
	public function getSequenceName($sqn)
	{
		return sprintf($this->conn->getAttribute(Doctrine_Core::ATTR_SEQNAME_FORMAT),
		preg_replace('/[^a-z0-9_\$.]/i', '_', $sqn));
	}

	/**
	 * adds index name formatting to a index name
	 *
	 * @param string    name of the index
	 * @return string   formatted index name
	 */
	public function getIndexName($idx)
	{
		return sprintf($this->conn->getAttribute(Doctrine_Core::ATTR_IDXNAME_FORMAT),
		preg_replace('/[^a-z0-9_\$]/i', '_', $idx));
	}

	/**
	 * Formatting a foreign Key name
	 *
	 * @param string    name of the foreign key
	 * @return string   formatted foreign key name
	 */
	public function getForeignKeyName($fkey)
	{
		return preg_replace('/[^a-z0-9_\$]/i', '_', $fkey);
	}

	/**
	 * adds table name formatting to a table name
	 *
	 * @param string    name of the table
	 * @return string   formatted table name
	 */
	public function getTableName($table)
	{
		$format = $this->conn->getAttribute(Doctrine_Core::ATTR_TBLNAME_FORMAT);
		return sprintf($format, str_replace(sprintf($format, null), null, $table));
	}
}
